/* $Id: log.c 3752 2011-09-18 14:38:46Z bennylp $ */
/* 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */
 
 
 #if 0
#include <CSVT/types.h>
#include <CSVT/log.h>
#include <CSVT/string.h>
#include <CSVT/os.h>
#include <CSVT/compat/stdarg.h>
#endif



#include<stdlib.h>
#include "log.h"





//static int CSVT_log_max_level = CSVT_LOG_MAX_LEVEL;








#define LOG_MAX_INDENT		80


static void logging_shutdown(void)
{
    return ;


}



static void log_set_indent(struct csvt_domain_log *obj,int indent)
{
    obj->log_indent = indent;
    if (obj->log_indent < 0) obj->log_indent = 0;
}

static int log_get_raw_indent(struct csvt_domain_log *obj)
{
    return obj->log_indent;
}


static int log_get_indent(struct csvt_domain_log *obj)
{
    int indent = log_get_raw_indent(obj);
    return indent > LOG_MAX_INDENT ? LOG_MAX_INDENT : indent;
}

void CSVT_log_add_indent(struct csvt_domain_log *obj,int indent)
{
    log_set_indent(obj,log_get_raw_indent(obj) + indent);
}

void CSVT_log_push_indent(struct csvt_domain_log *obj)
{
    CSVT_log_add_indent(obj,CSVT_LOG_INDENT_SIZE);
}

void CSVT_log_pop_indent(struct csvt_domain_log *obj)
{
    CSVT_log_add_indent(obj,-CSVT_LOG_INDENT_SIZE);
}

CSVT_status_t CSVT_log_init(struct csvt_domain_log *obj)
{
    
    //printf("%d\n",__LINE__);
    if(obj->registered){
        
        unsigned log_decor =CSVT_LOG_HAS_DAY_NAME|CSVT_LOG_HAS_YEAR|
                CSVT_LOG_HAS_MONTH|CSVT_LOG_HAS_DAY_OF_MON|
                CSVT_LOG_HAS_LEVEL_TEXT|CSVT_LOG_HAS_FUNCIONT_NAME|
                CSVT_LOG_HAS_TIME | CSVT_LOG_HAS_MICRO_SEC |
			    CSVT_LOG_HAS_SENDER | CSVT_LOG_HAS_NEWLINE |
			    CSVT_LOG_HAS_SPACE | CSVT_LOG_HAS_THREAD_SWC |
			    CSVT_LOG_HAS_INDENT |CSVT_LOG_HAS_LINE   ;
	    
        CSVT_log_set_level(obj,6);
		int i=0;
		for(i=0;i<obj->log_max_level+1;i++)
			CSVT_log_set_log_func(obj,i,CSVT_log_write);
		char filename[128]={0};
		sprintf(filename,"./err_.log",obj->name);
		obj->fp[1]=fopen(filename,"w");
		CSVT_log_set_log_func(obj,1,CSVT_log_write_to_file);
        CSVT_log_set_decor(obj,log_decor|CSVT_LOG_HAS_COLOR);
		///CSVT_log_set_decor();
		CSVT_log_set_color(obj,1,CSVT_TERM_COLOR_R);
		CSVT_log_set_color(obj,2,CSVT_TERM_COLOR_R|CSVT_TERM_COLOR_G);
		CSVT_log_set_color(obj,3,CSVT_TERM_COLOR_G);
		CSVT_log_set_color(obj,4,CSVT_TERM_COLOR_B);//
		CSVT_log_set_color(obj,5,CSVT_TERM_COLOR_R|CSVT_TERM_COLOR_B);//
		//CSVT_log_set_color(obj,6,CSVT_TERM_COLOR_R|CSVT_TERM_COLOR_G|CSVT_TERM_COLOR_B);//
		//CSVT_log_set_color(obj,6,CSVT_TERM_COLOR_R|CSVT_TERM_COLOR_G|CSVT_TERM_COLOR_B);//
        CSVT_log_set_color(obj,6,0);//
        obj->E=CSVT_log_1;
        obj->W=CSVT_log_2;
        obj->I=CSVT_log_3;
        obj->D=CSVT_log_4;
        obj->T=CSVT_log_5;
        obj->V=CSVT_log_6;
    }else{
        obj->E=CSVT_log_null;
        obj->W=CSVT_log_null;
        obj->I=CSVT_log_null;
        obj->D=CSVT_log_null;
        obj->T=CSVT_log_null;
        obj->V=CSVT_log_null;
    }
    return CSVT_SUCCESS;
}

CSVT_status_t CSVT_log_exit(struct csvt_domain_log *obj)
{
	int i=0;
	FILE*fp=NULL;
	for(i=0;i<obj->log_max_level+1;i++){
		fp=obj->fp[i];
		if(fp)
			fclose(fp);
	}
}
void CSVT_log_set_decor(struct csvt_domain_log *obj,unsigned decor)
{
    obj->log_decor = decor;
}

unsigned CSVT_log_get_decor(struct csvt_domain_log *obj)
{
    return obj->log_decor;
}

void CSVT_log_set_color(struct csvt_domain_log *obj,int level, CSVT_color_t color)
{
    switch (level) 
    {
	case 0: obj->log_level_color[0] = color; 
	    break;
	case 1: obj->log_level_color[1] = color;
	    break;
	case 2: obj->log_level_color[2] = color; 
	    break;
	case 3: obj->log_level_color[3] = color; 
	    break;
	case 4: obj->log_level_color[4] = color; 
	    break;
	case 5: obj->log_level_color[5] = color;
	    break;
	case 6: obj->log_level_color[6] = color; 
	    break;
	/* Default terminal color */
	case 77: obj->log_level_color[7] = color;
	    break;
	default:
	    /* Do nothing */
	    break;
    }
}

CSVT_color_t CSVT_log_get_color(struct csvt_domain_log *obj,int level)
{
    switch (level) {
	case 0:
	    return obj->log_level_color[0];
	case 1:
	    return obj->log_level_color[1];
	case 2:
	    return obj->log_level_color[2];
	case 3:
	    return obj->log_level_color[3];
	case 4:
	    return obj->log_level_color[4];
	case 5:
	    return obj->log_level_color[5];
	case 6:
	    return obj->log_level_color[6];
	default:
	    /* Return default terminal color */
	    return obj->log_level_color[7];
    }
}

void CSVT_log_set_level(struct csvt_domain_log *obj,int level)
{
    obj->log_max_level = level;
}


int CSVT_log_get_level(struct csvt_domain_log *obj)
{
    return obj->log_max_level;
}


void CSVT_log_set_log_func( struct csvt_domain_log *obj,int level,CSVT_log_func *func )
{
	if(level>=0&&level<=6)
		obj->log_writer[level] = func;
}

CSVT_log_func* CSVT_log_get_log_func(struct csvt_domain_log *obj,int level)
{
	if(level>=0&&level<=6)
		return obj->log_writer[level];
	return NULL;
}

/* Temporarily suspend logging facility for this thread.
 * If thread local storage/variable is not used or not initialized, then
 * we can only suspend the logging globally across all threads. This may
 * happen e.g. when log function is called before CSVTLIB is fully initialized
 * or after CSVTLIB is shutdown.
 */
static void suspend_logging(struct csvt_domain_log *obj,int *saved_level)
{
    
    return ;
    
}

/* Resume logging facility for this thread */
static void resume_logging(struct csvt_domain_log *obj,int *saved_level)
{

   
}

/* Is logging facility suspended for this thread? */
static CSVT_bool_t is_logging_suspended(struct csvt_domain_log *obj)
{

    return obj->log_max_level== 0;
   
}
/*
 * Time.
 */

CSVT_status_t CSVT_gettimeofday(CSVT_time_val *tv)
{
    struct timeval tval;
  
    //do_gettimeofday(&tval);
    gettimeofday(&tval,NULL);
    tv->sec = tval.tv_sec;
    tv->msec = tval.tv_usec / 1000;

    return 0;
}


CSVT_status_t CSVT_time_decode(const CSVT_time_val *tv, CSVT_parsed_time *pt)
{
     struct tm *local_time;

  

    local_time = localtime((time_t*)&tv->sec);

    pt->year = local_time->tm_year+1900;
    pt->mon = local_time->tm_mon;
    pt->day = local_time->tm_mday;
    pt->hour = local_time->tm_hour;
    pt->min = local_time->tm_min;
    pt->sec = local_time->tm_sec;
    pt->wday = local_time->tm_wday;
    pt->msec = tv->msec;

}
void CSVT_log( struct csvt_domain_log *obj,const char *sender, int level, 
		     const char *format, va_list marker)
{
    CSVT_time_val now;
    CSVT_parsed_time ptime;
    char *pre;

    char log_buffer[2048];

    int saved_level, len, print_len, indent;

    //CSVT_CHECK_STACK();
    
    if (level > obj->log_max_level)
	return;

    if (is_logging_suspended(obj))
	return;

    /* Temporarily disable logging for this thread. Some of CSVTLIB APIs that
     * this function calls below will recursively call the logging function 
     * back, hence it will cause infinite recursive calls if we allow that.
     */
    suspend_logging(obj,&saved_level);

    /* Get current date/time. */
    CSVT_gettimeofday(&now);
    CSVT_time_decode(&now, &ptime);

    pre = log_buffer;
    if (obj->log_decor & CSVT_LOG_HAS_LEVEL_TEXT) {
	static const char *ltexts[] = { "FATAL:   ", "[ERROR]   ", "[WARN]    ", 
			      "[INFO]     ", "[DEBUG]   ", "[TRACE]   ", "[VERBOSE] "};
	strcpy(pre, ltexts[level]);
	pre += 10;
    }
    if (obj->log_decor & CSVT_LOG_HAS_DAY_NAME) {
	static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",
				       "Thu", "Fri", "Sat"};
	strcpy(pre, wdays[ptime.wday]);
	pre += 3;
    }
    if (obj->log_decor & CSVT_LOG_HAS_YEAR) {
	if (pre!=log_buffer) *pre++ = ' ';
	pre += CSVT_utoa(ptime.year, pre);
    }
    if (obj->log_decor & CSVT_LOG_HAS_MONTH) {
	*pre++ = '-';
	pre += CSVT_utoa_pad(ptime.mon+1, pre, 2, '0');
    }
    if (obj->log_decor & CSVT_LOG_HAS_DAY_OF_MON) {
	*pre++ = '-';
	pre += CSVT_utoa_pad(ptime.day, pre, 2, '0');
    }
    if (obj->log_decor & CSVT_LOG_HAS_TIME) {
	if (pre!=log_buffer) *pre++ = ' ';
	pre += CSVT_utoa_pad(ptime.hour, pre, 2, '0');
	*pre++ = ':';
	pre += CSVT_utoa_pad(ptime.min, pre, 2, '0');
	*pre++ = ':';
	pre += CSVT_utoa_pad(ptime.sec, pre, 2, '0');
    }
    if (obj->log_decor & CSVT_LOG_HAS_MICRO_SEC) {
	*pre++ = '.';
	pre += CSVT_utoa_pad(ptime.msec, pre, 3, '0');
    }
    if (obj->log_decor & CSVT_LOG_HAS_SENDER) {
	enum { SENDER_WIDTH = 14 };
	int sender_len = strlen(sender);
	if (pre!=log_buffer) *pre++ = ' ';
	if (sender_len <= SENDER_WIDTH) {
	    while (sender_len < SENDER_WIDTH)
		*pre++ = ' ', ++sender_len;
	    while (*sender)
		*pre++ = *sender++;
	} else {
	    int i;
	    for (i=0; i<SENDER_WIDTH; ++i)
		*pre++ = *sender++;
	}
    }
   
    if (obj->log_decor & CSVT_LOG_HAS_FUNCIONT_NAME) {
    	#if 0
    	enum { THREAD_WIDTH = 14 };
    	
    	//const char *thread_name = CSVT_thread_get_name(0);
    	//int thread_len = strlen(thread_name);
    	const   char *fun_name=obj->fun_name;
    	int fun_name_len = strlen(fun_name);
    	*pre++ = ' ';
    	if (fun_name_len <= THREAD_WIDTH) {
    	    while (fun_name_len < THREAD_WIDTH)
    		*pre++ = ' ', ++fun_name_len;
    	    while (*fun_name)
    		*pre++ = *fun_name++;
    	} else {
    	    int i;
    	    for (i=0; i<THREAD_WIDTH; ++i)
    		*pre++ = *fun_name++;
    	}
    	#endif
    	const   char *fun_name=obj->fun_name;
    	int fun_name_len = strlen(fun_name);
    	*pre++ = ' ';
    	sprintf(pre,"%s",fun_name);
    	pre+=fun_name_len;
    	    /*here add Enter*/
    	    //*pre='\n';
    	   // pre++;
    }
     
     if(obj->log_decor & CSVT_LOG_HAS_LINE){   
        enum { LINE_WIDTH = 8 };
        if (pre!=log_buffer) *pre++ = ' ';
        snprintf(pre,LINE_WIDTH+1,"%8d",obj->line_ptr);
        pre+=LINE_WIDTH;
    }
    if (obj->log_decor != 0 && obj->log_decor != CSVT_LOG_HAS_NEWLINE)
	*pre++ = ' ';

    if (obj->log_decor & CSVT_LOG_HAS_THREAD_SWC) {
        
      
    } else if (obj->log_decor & CSVT_LOG_HAS_SPACE) {
	*pre++ = ' ';
    }


    char CSVT_LOG_INDENT_CHAR='.';
    if (obj->log_decor & CSVT_LOG_HAS_INDENT) {
	indent = log_get_indent(obj);
	if (indent > 0) {
	    memset(pre, CSVT_LOG_INDENT_CHAR, indent);
	    pre += indent;
	}
    }


    len = pre - log_buffer;

    /* Print the whole message to the string log_buffer. */
    print_len = vsnprintf(pre, sizeof(log_buffer)-len, format, 
				  marker);
    if (print_len < 0) {
	level = 1;
	print_len = snprintf(pre, sizeof(log_buffer)-len, 
				     "<logging error: msg too long>");
    }
    len = len + print_len;
    if (len > 0 && len < (int)sizeof(log_buffer)-2) {
	if (obj->log_decor & CSVT_LOG_HAS_CR) {
	    log_buffer[len++] = '\r';
	}
	if (obj->log_decor & CSVT_LOG_HAS_NEWLINE) {
	    log_buffer[len++] = '\n';
	}
	log_buffer[len] = '\0';
    } else {
	len = sizeof(log_buffer)-1;
	if (obj->log_decor & CSVT_LOG_HAS_CR) {
	    log_buffer[sizeof(log_buffer)-3] = '\r';
	}
	if (obj->log_decor & CSVT_LOG_HAS_NEWLINE) {
	    log_buffer[sizeof(log_buffer)-2] = '\n';
	}
	log_buffer[sizeof(log_buffer)-1] = '\0';
    }

    /* It should be safe to resume logging at this point. Application can
     * recursively call the logging function inside the callback.
     */
    resume_logging(obj,&saved_level);

    if (obj->log_writer[level])
	(*(obj->log_writer[level]))(obj,level, log_buffer, len);
}


void CSVT_log_0(struct csvt_domain_log *obj,const char *sender, const char *format, va_list arg)
{
    //va_list arg;
    //va_start(arg, format);
    CSVT_log(obj,sender, 0, format, arg);
    //va_end(arg);
}


void CSVT_log_1(struct csvt_domain_log *obj,const char *sender, const char *format, va_list arg)
{
   // printf("%d\n",__LINE__);
    //va_list arg;
    //va_start(arg, format);
    CSVT_log(obj,sender, 1, format, arg);
    //va_end(arg);
}



void CSVT_log_2(struct csvt_domain_log *obj,const char *sender, const char *format, va_list arg)
{
    //va_list arg;
    //va_start(arg, format);
    CSVT_log(obj,sender, 2, format, arg);
    //va_end(arg);
}



void CSVT_log_3(struct csvt_domain_log *obj,const char *sender, const char *format, va_list arg)
{
    //va_list arg;
    //va_start(arg, format);
    CSVT_log(obj,sender, 3, format, arg);
    //va_end(arg);
}



void CSVT_log_4(struct csvt_domain_log *obj,const char *sender, const char *format, va_list arg)
{
    //va_list arg;
    //va_start(arg, format);
    CSVT_log(obj,sender, 4, format, arg);
    //va_end(arg);
}


void CSVT_log_5(struct csvt_domain_log *obj,const char *sender, const char *format, va_list arg)
{
    //va_list arg;
    //va_start(arg, format);
    CSVT_log(obj,sender, 5, format, arg);
    //va_end(arg);
}



void CSVT_log_6(struct csvt_domain_log *obj,const char *sender, const char *format, va_list arg)
{
    //va_list arg;
    //va_start(arg, format);
    CSVT_log(obj,sender, 6, format, arg);
    //va_end(arg);
}

void CSVT_log_null(struct csvt_domain_log *obj,const char *sender, const char *format, va_list arg)
{
    /*do nonthing!*/
}


/*
 * Terminal
 */

/**
 * Set terminal color.
 */
CSVT_status_t CSVT_term_set_color(struct csvt_domain_log *obj,CSVT_color_t color)
{
    /* put bright prefix to ansi_color */
    char ansi_color[12] = "\033[01;3";
    if (color & CSVT_TERM_COLOR_BRIGHT) {
	color ^= CSVT_TERM_COLOR_BRIGHT;
    } else {
        strcpy(ansi_color, "\033[00;3");
    }

    switch (color) {
    case 0:
	/* black color */
	strcat(ansi_color, "0;1m");
	break;
    case CSVT_TERM_COLOR_R:
	/* red color */
	strcat(ansi_color, "1;1m");
	break;
    case CSVT_TERM_COLOR_G:
	/* green color */
	strcat(ansi_color, "2;1m");
	break;
    case CSVT_TERM_COLOR_B:
	/* blue color */
	strcat(ansi_color, "4;1m");
	break;
    case CSVT_TERM_COLOR_R | CSVT_TERM_COLOR_G:
	/* yellow color */
	strcat(ansi_color, "3;1m");
	break;
    case CSVT_TERM_COLOR_R | CSVT_TERM_COLOR_B:
	/* magenta color */
	strcat(ansi_color, "5;1m");
	break;
    case CSVT_TERM_COLOR_G | CSVT_TERM_COLOR_B:
	/* cyan color */
	strcat(ansi_color, "6;1m");
	break;
    case CSVT_TERM_COLOR_R | CSVT_TERM_COLOR_G | CSVT_TERM_COLOR_B:
	/* white color */
	strcat(ansi_color, "7;1m");
	break;
    default:
	/* default console color */
	strcpy(ansi_color, "\033[00m");
	break;
    }

    fputs(ansi_color, stdout);

    return CSVT_SUCCESS;
}

/**
 * Get current terminal foreground color.
 */
CSVT_color_t CSVT_term_get_color(struct csvt_domain_log *obj)
{
    return 0;
}

/**/

 void term_set_color(struct csvt_domain_log *obj,int level)
{

    CSVT_term_set_color(obj,CSVT_log_get_color(obj,level));


}

 void term_restore_color(struct csvt_domain_log *obj)
{

    /* Set terminal to its default color */
    CSVT_term_set_color(obj,CSVT_log_get_color(obj,77));

}


void CSVT_log_write(struct csvt_domain_log *obj,int level, const char *buffer, int len)
{
    //CSVT_CHECK_STACK();
    //CSVT_UNUSED_ARG(len);
		//printf("%d\n",__LINE__);

    /* Copy to terminal/file. */
    if (CSVT_log_get_decor(obj) & CSVT_LOG_HAS_COLOR) {
	term_set_color(obj,level);
	printf("%s", buffer);
	term_restore_color(obj);
    } else {
	printf("%s", buffer);
    }
}
void CSVT_log_write_to_file(struct csvt_domain_log *obj,int level, const char *buffer, int len)
{
    //CSVT_CHECK_STACK();
    //CSVT_UNUSED_ARG(len);
		//printf("%d\n",__LINE__);

    /* Copy to terminal/file. */
	FILE *fp=obj->fp[level];
    if(fp){
		fprintf(fp,"%s",buffer);
	}
	else{
		printf("%s", buffer);
	}
}



/*
 * OS.
 */



/*
 * CSVT_thread-get_name()
 */
const char* CSVT_thread_get_name(CSVT_thread_t *p)
{

    return "ThreadName!";
    //CSVT_thread_t *rec = (CSVT_thread_t*)p;

   // CSVT_CHECK_STACK();
    //CSVT_ASSERT_RETURN(p, "");

    //return rec->obj_name;

}

/*
 * String
 */
 
 
int CSVT_utoa(unsigned long val, char *buf)
{
    return CSVT_utoa_pad(val, buf, 0, 0);
}

int CSVT_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)
{
    char *p;
    int len;

    //CSVT_CHECK_STACK();

    p = buf;
    do {
        unsigned long digval = (unsigned long) (val % 10);
        val /= 10;
        *p++ = (char) (digval + '0');
    } while (val > 0);

    len = p-buf;
    while (len < min_dig) {
	*p++ = (char)pad;
	++len;
    }
    *p-- = '\0';

    do {
        char temp = *p;
        *p = *buf;
        *buf = temp;
        --p;
        ++buf;
    } while (buf < p);

    return len;
}



///////////////////////////////


 void csvt_domain_log_init( const char *name,csvt_domain_log *csvt )
{
   
	char * domain_name=getenv(csvt->name);
		if(domain_name!=NULL&&!strcmp(domain_name,"y")){
		printf("%s=y\n",csvt->name);
		csvt->registered=1;
		
	}else{
		printf("%s=n\n",name);
		csvt->registered=0;
	}
	CSVT_log_init(csvt);
}

void csvt_domain_log_exit( csvt_domain_log *csvt )
{
	if(csvt->registered){
		CSVT_log_exit(csvt);
	}
}
